
package java.util;

import java.util.function.Consumer;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.function.Supplier;

/**
 * 一个容器对象，可能包含非空值。如果值存在，{@code isPresent()} 将返回 {@code true}，并且 {@code get()} 将返回该值。
 * <p>提供了额外的方法来依赖值的存在或不存在，例如 {@link #orElse(java.lang.Object) orElse()}（如果值不存在返回默认值）
 * 和 {@link #ifPresent(java.util.function.Consumer) ifPresent()}（如果值存在执行一段代码）。
 *
 * <p>这是一个<a href="../lang/doc-files/ValueBased.html">基于值的</a>类；对 {@code Optional} 实例使用身份敏感操作（包括引用相等性（{@code ==}）、
 * 身份哈希码或同步）可能会有不可预测的结果，应避免这样做。
 *
 * @since 1.8
 */
public final class Optional<T> {

    /**
     * 用于 {@code empty()} 的通用实例。
     */
    private static final Optional<?> EMPTY = new Optional<>();

    /**
     * 如果非空，表示值；如果为空，则表示没有值存在。
     */
    private final T value;

    /**
     * 构造一个空的实例。
     * @implNote 通常每个 VM 只存在一个空实例 {@code Optional#EMPTY}。
     */
    private Optional() {
        this.value = null;
    }

    /**
     * 返回一个空的 {@code Optional} 实例。该实例没有值存在。
     * @param <T> 缺失值的类型
     * @return 一个空的 {@code Optional}
     * @apiNote 尽管可能很有诱惑力，但避免通过与 {@code Optional.empty()} 返回的实例使用 {@code ==} 进行比较来测试对象是否为空。
     * 没有保证该实例是单例。应使用 {@link #isPresent()} 方法。
     */
    public static <T> Optional<T> empty() {
        @SuppressWarnings("unchecked")
        Optional<T> t = (Optional<T>) EMPTY;
        return t;
    }

    /**
     * 构造一个值存在的实例。
     * @param value 非空的值，要存在该 {@code Optional} 中
     * @throws NullPointerException 如果值为 {@code null}
     */
    private Optional(T value) {
        this.value = Objects.requireNonNull(value);
    }

    /**
     * 返回一个具有指定非空值的 {@code Optional} 实例。
     * @param <T>   值的类型
     * @param value 要存在的值，必须非空
     * @return 一个具有指定值的 {@code Optional} 实例
     * @throws NullPointerException 如果值为 {@code null}
     */
    public static <T> Optional<T> of(T value) {
        return new Optional<>(value);
    }

    /**
     * 如果指定的值非空，返回一个具有该值的 {@code Optional} 实例，否则返回一个空的 {@code Optional}。
     * @param <T>   值的类型
     * @param value 可能为 {@code null} 的值
     * @return 如果指定的值非空，则返回一个具有该值的 {@code Optional}，否则返回一个空的 {@code Optional}
     */
    public static <T> Optional<T> ofNullable(T value) {
        return value == null ? empty() : of(value);
    }

    /**
     * 如果值存在，返回值，否则抛出 {@code NoSuchElementException}。
     * @return 存在于该 {@code Optional} 中的非空值
     * @throws NoSuchElementException 如果没有值存在
     * @see Optional#isPresent()
     */
    public T get() {
        if (value == null) {
            throw new NoSuchElementException("No value present");
        }
        return value;
    }

    /**
     * 如果值存在，返回 {@code true}，否则返回 {@code false}。
     * @return 如果值存在，返回 {@code true}，否则返回 {@code false}
     */
    public boolean isPresent() {
        return value != null;
    }

    /**
     * 如果值存在，执行给定的消费者接口中的操作。
     *
     * @param consumer 如果值存在，则要执行的操作
     * @throws NullPointerException 如果值存在但是 {@code consumer} 为 {@code null}
     */
    public void ifPresent(Consumer<? super T> consumer) {
        if (value != null)
            consumer.accept(value);
    }

    /**
     * 如果值存在且满足给定的条件，则返回一个包含该值的 {@code Optional}，否则返回一个空的 {@code Optional}。
     *
     * @param predicate 用于测试值的条件
     * @return 如果值存在且满足给定条件，则返回一个包含该值的 {@code Optional}，否则返回一个空的 {@code Optional}
     * @throws NullPointerException 如果 {@code predicate} 为 {@code null}
     */
    public Optional<T> filter(Predicate<? super T> predicate) {
        Objects.requireNonNull(predicate);
        if (!isPresent())
            return this;
        else
            return predicate.test(value) ? this : empty();
    }

    /**
     * 如果值存在，应用提供的映射函数于该值上，如果结果非空，则返回一个包含该结果的 {@code Optional}。
     *
     * @param <U>    映射函数结果的类型
     * @param mapper 用于转换值的映射函数
     * @return 一个包含映射函数应用于该值的结果的 {@code Optional}，如果值不存在或映射结果为 {@code null}，则返回一个空的 {@code Optional}
     * @throws NullPointerException 如果 {@code mapper} 为 {@code null}
     */
    public <U> Optional<U> map(Function<? super T, ? extends U> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Optional.ofNullable(mapper.apply(value));
        }
    }

    /**
     * 如果值存在，应用提供的 {@code Optional}-承载映射函数于该值上，返回该结果，否则返回一个空的 {@code Optional}。
     * 该方法与 {@link #map(Function)} 相似，但提供的映射函数结果已是 {@code Optional} 类型，此方法不会对其再包装。
     * @param <U>    映射函数结果的 {@code Optional} 类型
     * @param mapper 用于转换值的 {@code Optional}-承载映射函数
     * @return 该 {@code Optional} 中值的映射结果，如果值不存在，则返回一个空的 {@code Optional}
     * @throws NullPointerException 如果 {@code mapper} 为 {@code null} 或返回 {@code null}
     */
    public <U> Optional<U> flatMap(Function<? super T, Optional<U>> mapper) {
        Objects.requireNonNull(mapper);
        if (!isPresent())
            return empty();
        else {
            return Objects.requireNonNull(mapper.apply(value));
        }
    }

    /**
     * 如果值存在，返回该值，否则返回 {@code other}。
     *
     * @param other 如果没有值存在时返回的值，可以为 {@code null}
     * @return 如果值存在，则返回该值，否则返回 {@code other}
     */
    public T orElse(T other) {
        return value != null ? value : other;
    }

    /**
     * 如果值存在，返回该值，否则使用提供的供应者获取一个值。
     *
     * @param other 一个供应者，用于在没有值存在时提供一个值
     * @return 如果值存在则返回该值，否则返回 {@code other.get()}
     * @throws NullPointerException 如果值不存在且 {@code other} 为 {@code null}
     */
    public T orElseGet(Supplier<? extends T> other) {
        return value != null ? value : other.get();
    }

    /**
     * 如果值存在，返回该值，否则抛出由提供的供应商创建的异常。
     *
     * @param <X>               异常类型
     * @param exceptionSupplier 一个供应者，用于在没有值存在时创建并提供一个异常
     * @return 如果值存在则返回该值
     * @throws X                    如果值不存在，则抛出由 {@code exceptionSupplier.get()} 返回的异常
     * @throws NullPointerException 如果值不存在且 {@code exceptionSupplier} 为 {@code null}
     */
    public <X extends Throwable> T orElseThrow(Supplier<? extends X> exceptionSupplier) throws X {
        if (value != null) {
            return value;
        } else {
            throw exceptionSupplier.get();
        }
    }

    /**
     * 判断另一个对象是否等同于这个 Optional。当另一个对象满足以下条件时，认为它是等同的：
     * <ul>
     * <li>也是 an {@code Optional}；并且
     * <li>两者都没有值存在，或者
     * <li>存在的值通过 {@code equals()} 方法相互等同。
     * </ul>
     *
     * @param obj 要测试等同性的对象
     * @return 如果另一个对象等同于这个 Optional，则返回 {@code true}，否则返回 {@code false}
     */
    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }

        if (!(obj instanceof Optional)) {
            return false;
        }

        Optional<?> other = (Optional<?>) obj;
        return Objects.equals(value, other.value);
    }

    /**
     * 返回存在值的哈希码，如果不存在值则返回 0（零）。
     *
     * @return 存在值的哈希码，如果不存在值则返回 0
     */
    @Override
    public int hashCode() {
        return Objects.hashCode(value);
    }

    /**
     * 返回一个适合调试的非空字符串表示形式，该表示形式适当地反映了 Optional 的状态。
     * 具体的呈现格式在不同实现和版本之间可能有所不同。
     *
     * @return 该实例的字符串表示形式
     * @implSpec 如果存在值，结果必须包括其字符串表示形式。空和有值的 Optional 必须能够无歧义地区分开。
     */
    @Override
    public String toString() {
        return value != null
                ? String.format("Optional[%s]", value)
                : "Optional.empty";
    }
}
